import {AIConfig, LayaAPIAction, LayaAPICode, LayaAPIStatus} from "./AIConfig";
import { DemoServer } from "./AIDemo";
import { IDEAgent } from "./IDEAgent";
import {ISDAPIBody, ISDImg2ImgReq, parseCmd, post, SkyBoxGenData} from "./Imagen";

export type LayaAPIWait = {
    progress?: Function;
}
/**
 * @author Michael
 * @version 1.0
 * @Date 2023/8/21 19:36
 * @Description
 */
export class LayaAPI {
    /** 服务器返回的资源列表，如果使用向量数据库返回的地址有重复，则reuse=false再重新生成一遍*/
    private static genAssetsUrl:string[] = [];
    /** 用户信息 */
    private static userInfo: {userId:string, storeToken:string};
    /** 请求返回的结果 */
    private _requestRes: any;
    /** 请求的进度控制 */
    private _apiProgress: Function;
    /** 请求监听成功的间隔调用 */
    private _queryInterval: any;
    /**是否等待请求返回*/
    private _wait: boolean;

    static create(wait: boolean = true): LayaAPI{
        let res: LayaAPI = new LayaAPI(); //Laya.Pool.createByClass(LayaAPI);
        res._wait = wait;
        return res;
    }

    static setUserInfo(info: any){
        LayaAPI.userInfo = info;
    }

    /**
     * 格式化图片的路径
     * @param url
     */
    static formatImageUrl(url: string){
        if(url.startsWith('http://')||url.startsWith('https://'))
            return url;
        return AIConfig.imageStorage + url;
    }

    /**
     * 服务同步申请指申请的服务直接返回结果，无需异步查询。
     * 目前同步申请支持的服务只有：cmdparser 和 translation
     * @param action
     * @param params
     */
    async requestSync(action:string, params: any){
        let data: any = {};
        data.action = action;
        data.data = params;
        params.user_id = LayaAPI.userInfo.userId;
        params.token = LayaAPI.userInfo.storeToken;// LayaAPI.userInfo.token;

        this._requestRes = await post(AIConfig.layaApi+"/layame/aigc/request_sync",data);
        return this._requestRes && JSON.parse(this._requestRes);

    }
    /**
     * 请求laya服务器
     * @param action 行为名字
     * @param params 行为参数
     * @param progress API请求进度回调
     */
    async request(action:string, params: any, progress:Function = null) {
        let data: any = {};
        data.action = action;
        data.data = params;
        params.user_id = LayaAPI.userInfo.userId;
        params.token = LayaAPI.userInfo.storeToken;// LayaAPI.userInfo.token;
        this._apiProgress = progress;

        this._requestRes = await post(AIConfig.layaApi+"/layame/aigc/request",data);
        this._requestRes = JSON.parse(this._requestRes);

        if( this._wait ){
            return new Promise(async (resolve, reject)=>{
                if(this._requestRes.code !== 0){
                    const res: any = JSON.parse(JSON.stringify(this._requestRes));
                    this.recover();
                    resolve(res);
                }

                let timeoutId: any;
                let query: any = this._queryLoop();
                const timeoutPromise: Promise<any> = new Promise((resolve, reject) => {
                    timeoutId = setTimeout(() => {
                        resolve({code:0,data:{status:LayaAPIStatus.TaskStatusTimeout}});
                    }, 6000000);
                });

                let res: any = await Promise.race([query, timeoutPromise]).finally(()=>{
                    clearTimeout(timeoutId);
                });
                resolve(res);
                this.recover();
            })
        }
    }

    /**
     *调用laya_query接口，查询任务是否结束，如果没有结束的话，等待一秒后继续查找，直到返回任务结束。10秒后如果还没有返回结束，则认为调用失败
     */
    private async _queryLoop() {
        let queryRes: any = await this.query();
        if (queryRes) {
            queryRes = JSON.parse(queryRes);
            this._apiProgress && this._apiProgress(queryRes);
            if (queryRes.code === 0 && queryRes.data.status >= LayaAPIStatus.TaskStatusDone) {
                return queryRes;
            }else{
                return new Promise((resolve, reject)=>{
                    setTimeout(()=>{
                        resolve(this._queryLoop());
                    },200);
                });
            }
        }
        return null;
    }


    /**
     * 请求laya服务器
     */
    async query() {
        if(!this._requestRes || this._requestRes.code !== 0) return null;

        const task_id:string = this._requestRes.data.task_id;
        let data: any = {
            action: "query"
        };
        data.data = {
            token: LayaAPI.userInfo.storeToken,// LayaAPI.userInfo.token,
            task_id: task_id
        };
        return await post(AIConfig.layaApi+"/layame/aigc/query",data);
    }

    /**
     * 调用layaApi中的文心一言接口
     * @param msg
     */
    async laya_ernie_bot(msg: string){
        return this.request(LayaAPIAction.ernieBot,{
            prompt:msg
        });
    }

    async laya_chatgpt(msg:string){
        let r1 = await DemoServer.onChatGPT(LayaAPIAction.chatgpt,msg);
        if(r1) return r1;
    
        return this.request(LayaAPIAction.chatgpt,{
            prompt:msg
        });
    }

    /**
     * 调用layaApi中的文心一言接口
     * @param msg
     */
    async laya_cmd_parser(msg: string){
        if(false){
            return await this.requestSync(LayaAPIAction.cmdparser,{
                prompt:msg
            });
        }else{
            let r = await parseCmd(msg, null, AIConfig.cmdParseLogUrl);
            return {code:0,data:{status:LayaAPIStatus.TaskStatusDone,data:r}}
        }
    }

    /**
     * 生成音乐
     * @param msg            提示信息
     * @param duration       音乐时长，单位秒
     * @param temperature    温度
     * @param mode           模型
     * @param reuse          是否使用向量数据库
     */
    async laya_generate_music(msg: string,duration: number = 10,temperature: number = 1, mode: number = 1,refMusic:string=null, reuse: boolean = true): Promise<any>{
        let data: any = {
            prompt:msg,
            duration:duration,
            temperature:temperature,
            mode:mode,
            reference:refMusic,
            trans:true
        };
        reuse && (data.reuse = reuse);

        let res: any = await this.request(LayaAPIAction.generate_music,data);
        const resData: any = res && res.data;
        if(res && res.code === LayaAPICode.CodeSuccess && res.data.status == LayaAPIStatus.TaskStatusDone){
            const url: string = resData.url;
            if(resData.reuse == 1){
                if(LayaAPI.genAssetsUrl.indexOf(url) != -1){
                    return this.laya_generate_music(msg,duration,temperature,mode,refMusic,false);
                }
            }
            LayaAPI.genAssetsUrl.push(url);
        }
        return res;
    }

    /**
     * 翻译
     * @param msg 输入的汉字
     */
    async laya_translate(msg: string): Promise<any> {
        return await this.requestSync(LayaAPIAction.translation,{
            prompt:msg
        });
    }

    /**
     * 文字生成图片
     * @param data 生成图片需要的信息
     */
    async laya_text2img(data: ISDAPIBody): Promise<any> {
        let res: any = await this.request(LayaAPIAction.text_to_image,data);
        const resData: any = res && res.data;
        if(res && res.code === LayaAPICode.CodeSuccess && res.data.status == LayaAPIStatus.TaskStatusDone){
            const url: string = resData.images[0];
            if(resData.reuse == 1){
                if(LayaAPI.genAssetsUrl.indexOf(url) != -1){
                    data.reuse = false;
                    return this.laya_text2img(data);
                }
            }
            LayaAPI.genAssetsUrl.push(url);
        }
        return res;
    }

    /**
     * 图片生成图片
     * @param data 生成图片需要的信息
     */
    async laya_img2img(data: ISDImg2ImgReq): Promise<any> {
        return await this.request(LayaAPIAction.image_to_image,data);
    }

    /**
     * 生成天空盒
     * @param data 生成天空盒需要的信息
     */
    async laya_text2SkyBox(data: SkyBoxGenData): Promise<any> {
        let res: any = await this.request(LayaAPIAction.generate_skybox,data);
        const resData: any = res && res.data;
        if(res && res.code === LayaAPICode.CodeSuccess && res.data.status == LayaAPIStatus.TaskStatusDone){
            const url: string = resData.url;
            if(resData.reuse == 1){
                if(LayaAPI.genAssetsUrl.indexOf(url) != -1){
                    data.reuse = false;
                    return this.laya_text2SkyBox(data);
                }
            }
            LayaAPI.genAssetsUrl.push(url);
        }
        return res;
    }

    private clear(){
        this._requestRes = null;
        this._apiProgress = null;
        this._queryInterval = null;
    }

    recover(){
        this.clear();
    }
}


